#include "zen_gles3.h"
#include "zen_gles3_kit.h"

#pragma comment(lib, "libEGL.lib")
#pragma comment(lib, "libGLESv2.lib")
#pragma comment(lib, "OpenAL32.lib")

#include "zen_egl.h"

#include "zen_app_windows.h"

#include "gles3/gl3.h"

#include "zen_game_activity.h"
#include "zen_game_figure.h"
#include "zen_game_action.h"
#include "zen_game_scene.h"
#include "zen_game_sprite.h"
#include "zen_game_label.h"
#include "zen_game_dust.h"
#include "zen_file.h"

#include "zen_random.h"
#include <bitset>
#include "zen_audio_player.h"

Zen::Random mR;

class LifeGame
{
public:
	void Init(int width, int height, int percent)
	{
		mWidth = width;
		mHeight = height;
		mStates.assign(width * height, false);
		//for (size_t i = 0; i < mStates.size(); ++i)
		//{
		//	if ((int)mR.Next(100) < percent)
		//	{
		//		mStates.at(i) = true;
		//	}
		//}
		diffs.push_back(-mWidth - 1);
		diffs.push_back(-mWidth);
		diffs.push_back(-mWidth + 1);
		diffs.push_back(-1);
		diffs.push_back(0);
		diffs.push_back(1);
		diffs.push_back(mWidth - 1);
		diffs.push_back(mWidth);
		diffs.push_back(mWidth + 1);
	}
	void Update()
	{
		std::set<int> birth = { 4 };
		std::set<int> live = { 3, 4 };
		auto newState = mStates;
		for (size_t i = mWidth + 1; i < mStates.size() - mWidth - 1; ++i)
		{
			int v = GetValue(i);
			if (!newState.at(i))
			{
				if (birth.find(v) != birth.end())
				{
					newState.at(i) = true;
				}
			}
			else
			{
				if (live.find(v) == live.end())
				{
					newState.at(i) = false;
				}
			}
			//if (v == 0)
			//{
			//	if (mR.Next(9000000) == 0)
			//	{
			//		newState.at(i) = true;
			//		continue;
			//	}
			//}
		}
		mStates.swap(newState);
	}
	void AddPulse()
	{
		int y = mHeight / 2;
		int x = mWidth / 2;
		int c = y * mWidth + x;
		int len = 200;
		for (int i = -len; i <= len; ++i)
		{
			mStates.at(i + c) = true;
			mStates.at((y + i) * mWidth + x) = true;
		}
		//mStates.at(c) = true;
		//mStates.at(c - 1) = true;
		//mStates.at(c + 1) = true;
	}
	int GetValue(int index)
	{
		int v = 0;
		for (auto i : diffs)
		{
			if (mStates.at(i + index)) ++v;
		}
		return v;
	}
	bool IsAlive(int x, int y)
	{
		return mStates.at(x + y * mWidth);
	}

	int mWidth = 0;
	int mHeight = 0;
	std::vector<bool> mStates;
	std::vector<int> diffs;
};

class AppD : public Zen::Game::ActivityDelegate
{
	Zen::GL::Window* glWin{};

	std::shared_ptr<Zen::Game::Node> mScene;

	std::shared_ptr<Zen::Game::TextureCache> mTC;
	std::shared_ptr<Zen::AudioCache> mAC;

	std::shared_ptr<Zen::AudioPlayer> mPlayer;

	LifeGame mLifeGame;

public:
	void loadScene()
	{
		auto act = Zen::Game::Activity::Only();
		auto scene = act->GetRoot()->CreateInnerNode<Zen::Game::Scene>();
		scene->GetCamera()->Orthogonal(act->GetScreenSize());
		mScene = scene;
	}
	void initActivity()
	{
		auto engine = Zen::Graphics::Engine::GLES();
		Zen::GL::Render::CullFace(Zen::GL::EFace::None);
		engine->SetClearColor(Zen::EColor::Black);
		engine->SetClockwiseAsFront(false);
		Zen::Game::Activity::Only()->SetGraphicsEngine(engine);
	}
	void initCache()
	{
		auto act = Zen::Game::Activity::Only();

		mTC = std::make_shared<Zen::Game::TextureCache>(act->GetGraphicsEngine());

		mTC->AddImage("tex0", Zen::Game::BuiltinImages::Only()->CreateCircleTexture(Zen::EPixel::RGBA, 128));

		mPlayer = Zen::AudioPlayer::CreatePlayer();
		mAC = mPlayer->GetCache();
		mAC->SetDelegate(std::make_shared<Zen::WavAudioLoader>());
		mAC->Get("tianhu.wav");
	}
	virtual void OnLaunch()
	{
		initActivity();
		initCache();
		loadScene();
		//loadLabel();
		loadPoints();
		addTouch();

		playAudio();
	}
	void playAudio()
	{
		//mPlayer->Play(mAC->Get("1.wav"), false);
	}
	void addTouch()
	{
		auto touch = std::make_shared<Zen::Game::DefaultTouchHandle>();
		touch->SetObjectName("touch");
		touch->TouchDownCallback() = [this](Zen::AppTouch const& touch) mutable -> bool {
			std::cout << "touch down" << std::endl;
			mLifeGame.AddPulse();
			return true;
		};
		Zen::Game::Activity::Only()->GetTouchDispatcher()->AddTouchHandle(touch, 0, mScene, true);
	}
	void loadPoints()
	{
		mLifeGame.Init(800, 800, 1);
		auto ss = Zen::Game::Activity::Only()->GetScreenSize();
		auto lifes = mScene->CreateInnerNode<Zen::Game::FigureBrief>();
		lifes->SetColor(Zen::EColor::White);
		lifes->SetSize({ 1, 1 });
		lifes->SetAnchor({ 0, 0 });
		lifes->SetDrawMode(Zen::Graphics::EDrawMode::Point);

		auto action = Zen::Game::ActionCall::Generate(
			[this, lifes](float delay, int) {
				std::vector<Zen::Point2> points;
				mLifeGame.Update();
				for (int x = 0; x < mLifeGame.mWidth; ++x)
				{
					for (int y = 0; y < mLifeGame.mHeight; ++y)
					{
						if (mLifeGame.IsAlive(x, y))
						{
							points.push_back({ (float)x, (float)y });
						}
					}
				}
				lifes->SetPolygon(points);
				return true;
			},
			0, 0, 0.f);
		Zen::Game::Activity::Only()->GetActionDispather()->RunAction(action, lifes);
	}

	void loadLabel()
	{
		auto act = Zen::Game::Activity::Only();
		auto vs = act->GetScreenSize();

		auto font = Zen::Font::Generate(Zen::File::LoadFileToBuffer("D:/Fonts/arial.ttf"));
		auto brush = Zen::FontBrush::Generate(font, 32);
		auto textr = std::make_shared<Zen::Game::DefaultTextRender>(brush);

		auto node = mScene->CreateInnerNode<Zen::Game::TextLabel>();
		node->SetTextRender(textr);
		node->SetFontSize(20);
		node->SetText("hello");
		node->SetPosition({ 50, 50 });
		node->SetColor(Zen::EColor::Red);
		node->SetBlend(Zen::Graphics::EBlend::Normal);
		node->SetFlipX(true);
		node->SetFlipY(true);
		auto action = Zen::Game::ActionCall::Generate(
			[node](float delay, int) {
				node->SetText("fps:" + std::to_string(Zen::Game::Activity::Only()->GetRealFPS()));
				return true;
			},
			0, 0, 2.f);
		Zen::Game::Activity::Only()->GetActionDispather()->RunAction(action, node);
	}

	virtual void OnResize() {}

	virtual void OnPause() {}

	virtual void OnResume() {}

	virtual void OnExit() {}

	virtual void OnEvent(std::string event) {}
};

std::shared_ptr<Zen::AppDelegate> ZenAppMain(Zen::AppConfig* config)
{
	config->WindowHeight = 800;
	config->WindowWidth = 800;
	config->FramesPerSecond = 60.f;
	config->Title = "I";

	Zen::Game::Activity::Only()->SetDelegate(std::make_shared<AppD>());

	return Zen::Game::Activity::Only();
}
